/*
 * Message.cpp
 *
 *  Created on: Sep 8, 2012
 *      Author: dimir
 */

#include "Message.h"

Message::Message() {

	client_ptr = NULL;
	server = NULL;
	client_id = 0;
	data = NULL;
	to = 0;
	from = 0;
	t_message = MESSAGE;
	dbg_msg(LOG_TRACE, "Constructor of class MESSAGE");
	return ;
}

Message::Message(const Message& msg){
	if (&msg == this)
		return;
	this->client_id = msg.client_id;
	this->client_ptr = msg.client_ptr;
	this->clnts = clients(msg.clnts);
	if (msg.data_len >0){
		this->data = (char *) malloc(msg.data_len);
		this->data = (char *)memcpy((void *) this->data, (void *) msg.data, msg.data_len);
	}else{
		this->data = NULL;
	}
	this->data_len = msg.data_len;
	this->from = msg.from;
	this->server = msg.server;
	this->t_message = msg.t_message;
	this->to = msg.to;
	return;
}

Message::Message(int len, char* buf){
	client_ptr = NULL;
	server = NULL;
	client_id = 0;
	data = NULL;
	to = 0;
	from = 0;
	t_message = MESSAGE;
	if (buf == NULL){
		dbg_msg(LOG_ERROR, "Unknown buffer in constructor of class MESSAGE");
		return ;
	}
	switch (buf[0]) {
		case 0:
			t_message = MESSAGE;
			break;
		case 1:
			t_message = REGISTRATION;
			break;
		case 2:
			t_message = GET_CLIENTS;
			break;
		case 3:
			t_message = RESPONSE_REGISTRATION;
			break;
		case 4:
			t_message = RESPONSE_UNREGISTRATION;
			break;
		case 5:
			t_message = RESPONSE_CLIENTS;
			break;
		case 6:
			t_message = EXIT;
			break;
		default:
			dbg_msg(LOG_ERROR, "Unknown type of message.\n In constructor of class Message");
			return ;
	}
	size_t number_clients;
	u_int32_t temp_id;
	switch (t_message) {
		case MESSAGE:
			// copy id 'from' from buf to field 'from'
			memcpy((void*) &from, (void*) (buf + 1), 4);
			// copy id 'to' from buf to field 'to'
			memcpy((void*) &to, (void*) (buf + 5), 4);
			// copy datalen from buf to field 'data_len'
			memcpy((void*) &data_len, (void*) (buf + 9), 4);
			// copy data from buffer in message to field data
			data = (char *) malloc(data_len);
			data = (char *) memcpy((void *)data,(void *) (buf + 13), 4 );
			break;
		case REGISTRATION:
			// copy client id from buffer to field client_id
			memcpy((void*) &client_id, (void*) (buf + 1), 4);
			// copy client_ptr from buffer to field client_id
			memcpy((void*) &client_ptr, (void *) (buf + 5), 4);
			break;
		case GET_CLIENTS:
			// copy client_id from buffer to field client_id
			memcpy((void*) &client_id, (void*) (buf + 1), 4);
			break;
		case RESPONSE_REGISTRATION:
		case RESPONSE_UNREGISTRATION:
			break;
		case RESPONSE_CLIENTS:
			//fill vector of id of clients
			//copy number of id in buffer
			memcpy((void *) &number_clients, (void*) (buf + 1), 4);
			for (size_t i = 0; i < number_clients; i ++){
				memcpy((void *) &temp_id, (void*) (buf + 5 + i * 4), 4);
				clnts.push_back(temp_id);
			}
			break;
		case EXIT:
			// copy client_id from buffer to field 'client_id'
			memcpy((void*) &client_id, (void*) (buf + 1), 4);
			break;

	}
	return ;
}

std::ostream& operator <<(std::ostream& os, Message& msg){
	os << "object of class Message." << std::endl;
	os << "this = " << &msg << std::endl;
	if (msg.getType() == REGISTRATION || msg.getType() == GET_CLIENTS
			|| msg.getType() == EXIT)
		os << "id :" << msg.getClientId() << std::endl;
	if ((msg.getType() >= MESSAGE) && (msg.getType() <= EXIT))
		os << "type of message:" << TYPE_MESSAGE[msg.getType()] << "." << std::endl;
	switch (msg.getType()) {
		case MESSAGE:
			os << "from :" << msg.getFrom() << "\t" << "to:";
			if  (msg.getTo() == 0)
				os << "all";
			else
				os << msg.getTo();
			os << std::endl;
			os << "value of message :" << std::endl;
			os << std::string(msg.getData(), msg.getDataLen()) << std::endl;
			break;
		case REGISTRATION:
		case GET_CLIENTS:
			os << "from" << msg.getFrom() << std::endl;
			break;
		case RESPONSE_REGISTRATION:
		case RESPONSE_UNREGISTRATION:
			break;
		case RESPONSE_CLIENTS:
			os << "number of clients:" << msg.getClients().size() << std::endl;
			for (int i = 0; i < msg.getClients().size(); i++){
				os << "client#" << i << ":" << msg.getClients()[i] << std::endl;
			}
			break;
		case EXIT:
			os << "from" << msg.getFrom() << std::endl;
			break;
		default:
			os << "type of message: unknow." << std::endl;
			break;
	}
	return os;
}

TypeMessage Message::getType() const{
	return t_message;
}

char*	Message::getData() const{
	if (t_message == MESSAGE){
		return data;
	}else{
		dbg_msg(LOG_DEBUG, "Invalid format of message. \t Message::getData()");
		return NULL;
	}
}

u_int32_t Message::getDataLen() const{
	if (t_message == MESSAGE)
		return data_len;
	else
		dbg_msg(LOG_DEBUG, "Invalid format of message. \t Message::getDataLen()");
	return 0;
}

u_int32_t Message::getTo() const{
	if (t_message == MESSAGE){
		return to;
	}else{
		dbg_msg(LOG_DEBUG, "Invalid format of message.\t Message::getTo().");
	}
	return 0;
}
u_int32_t Message::getFrom() const{
	if (t_message == MESSAGE){
		return from;
	}else{
		dbg_msg(LOG_DEBUG, "Invalid format of message. \t Message:getFrom()");
	}
	return 0;
}
clients Message::getClients() const{
	if (t_message == RESPONSE_CLIENTS){
		return clnts;
	}else{
		dbg_msg(LOG_DEBUG, "invalid format of message.\t Message::getClients.");
	}
	return std::vector<u_int32_t>();
}

u_int32_t Message::getClientId() const{
	if ( (t_message == REGISTRATION) || (t_message == GET_CLIENTS) ||
			(t_message == EXIT)){
		return this->client_id;
	};
	dbg_msg(LOG_DEBUG, "Invalid format of message.\t Message::getClientId()");
	return 0xFFFFFFFF; // 2^32 - 1 - maximum - error
}
void * Message::getClientPtr() const{
	if (t_message == REGISTRATION){
		return this->client_ptr;
	}
	dbg_msg(LOG_DEBUG, "Invalid format of message.\t Message::getClienPtr()");
	return NULL;
}



void Message::clear(){
	if (data != NULL){
		free(data);
		data = NULL;
	}
	t_message = MESSAGE;
	server = NULL;
	client_ptr = NULL;
	to = from = data_len = client_id = 0;
	clnts.clear();
}

int Message::addMessage(u_int32_t from, u_int32_t to, const char* buf, const size_t buf_len){
	this->from = from;
	this->to = to;
	this->data =(char *) malloc(buf_len);
	this->data = (char *) memcpy((void *)this->data,(void *) buf, buf_len);
	this->data_len = buf_len;
	return 0;
}

int Message::addMessage(u_int32_t from, u_int32_t to, std::string& msg){
	this->from = from;
	this->to = to;
	this->data =(char *) malloc(msg.size() + 1);
	this->data = strcpy(this->data, msg.c_str());
	this->data_len = msg.length();
	return 0;
}


Message::~Message() {

	this->clear();
	dbg_msg(LOG_TRACE, "desctructor of class Message");
}

Message*
genMsg(const u_int32_t from, const u_int32_t to, const char* msg){
	Message* m = new Message();
	m->addMessage(from, to, msg, strlen(msg) + 1);
	return m;
}

Message*
genMsg(const u_int32_t from, const u_int32_t to, const char* buf, const size_t buf_len){
	Message* m = new Message();
	m->addMessage(from, to, buf, buf_len);
	return m;

}

Message*
genReqReg(const u_int32_t id, void* client_ptr){
	char* buf =(char *) malloc(9);
	buf[0] = REGISTRATION;
	memcpy((void *) (buf + 1),(void *) &id, 4);
	memcpy((void *) (buf + 5), (void *) & client_ptr, 4);
	Message* m = new Message(9, buf);
	free(buf);
	return m;
}
Message*
genReqGetClients(const u_int32_t id){
	char* buf =(char *) malloc(5);
	buf[0] = GET_CLIENTS;
	memcpy((void *) (buf + 1),(void *) &id, 4);
	Message* m = new Message(5, buf);
	free(buf);
	return m;

}

Message*
genRespReg(){
	char* buf =(char *) malloc(1);
	buf[0] = RESPONSE_REGISTRATION;
	Message* m = new Message(1, buf);
	free(buf);
	return m;
}
Message*
genRespUnreg(){
	char* buf =(char *) malloc(1);
	buf[0] = RESPONSE_UNREGISTRATION;
	Message* m = new Message(1, buf);
	free(buf);
	return m;
}


Message*
genRespClients(clients clnts){
	char* buf =(char *) malloc(5 + 4*clnts.size());
	buf[0] = RESPONSE_CLIENTS;
	u_int32_t n = clnts.size();
	memcpy((void *) (buf + 1),(void *) &n, 4);
	for(u_int32_t i = 0; i < n; i++){
		memcpy((void *) (buf + 5 + i*4),(void *) &(clnts[i]), 4);
	}
	Message* m = new Message(5 + 4*clnts.size(), buf);
	free(buf);
	return m;

}

Message*
genExit(const u_int32_t id){
	char* buf = (char *)malloc(5);
	buf[0] = EXIT;
	memcpy((void *) (buf + 1),(void *) &id, 4);
	Message* m = new Message(5, buf);
	free(buf);
	return m;
}

